package com.dtp.core.monitor;

import com.dtp.common.ApplicationContextHolder;
import com.dtp.core.support.ExecutorWrapper;
import com.dtp.common.entity.ThreadPoolStats;
import com.dtp.common.event.AlarmCheckEvent;
import com.dtp.common.event.CollectEvent;
import com.dtp.common.properties.DtpProperties;
import com.dtp.core.DtpRegistry;
import com.dtp.core.convert.MetricsConverter;
import com.dtp.core.handler.CollectorHandler;
import com.dtp.core.notify.manager.AlarmManager;
import com.dtp.core.thread.DtpExecutor;
import com.dtp.core.thread.NamedThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static com.dtp.common.constant.DynamicTpConst.SCHEDULE_NOTIFY_ITEMS;

/**
 * 动态线程池监视器
 *
 * @author yanhom
 * @since 1.0.0
 *
 * @remark muse
 **/
@Slf4j
public class DtpMonitor implements ApplicationRunner, Ordered {
    private static final ScheduledExecutorService MONITOR_EXECUTOR = new ScheduledThreadPoolExecutor(
            1, new NamedThreadFactory("dtp-monitor", true));

    @Resource
    private DtpProperties dtpProperties; // 动态线程池的主要配置属性

    /** monitorInterval：监控时间间隔（报警判断、指标采集），默认5s */
    @Override
    public void run(ApplicationArguments args) {
        MONITOR_EXECUTOR.scheduleWithFixedDelay(this::run, 0, dtpProperties.getMonitorInterval(), TimeUnit.SECONDS);
    }

    /** 监控任务 */
    private void run() {
        List<String> dtpNames = DtpRegistry.listAllDtpNames();          // 获得DTP_REGISTRY中所有DtpExecutor的线程池名称列表
        List<String> commonNames = DtpRegistry.listAllCommonNames();    // 获得COMMON_REGISTRY中所有D普通线程池名称列表
        checkAlarm(dtpNames);               // 针对Dtp执行器的警告检测
        collect(dtpNames, commonNames);     // 收集线程池状态
    }

    /** 警告检测 */
    private void checkAlarm(List<String> dtpNames) {
        dtpNames.forEach(x -> {
            DtpExecutor executor = DtpRegistry.getDtpExecutor(x);       // 依次获得dtp线程池
            AlarmManager.doAlarmAsync(executor, SCHEDULE_NOTIFY_ITEMS); // 针对LIVENESS和CAPACITY，发送警告消息
        });

        publishAlarmCheckEvent(); // 发布报警事件
    }

    /** 线程池状态信息收集操作 */
    private void collect(List<String> dtpNames, List<String> commonNames) {
        if (!dtpProperties.isEnabledCollect()) return;

        // 针对Dtp执行器收集线程池状态
        dtpNames.forEach(x -> {
            DtpExecutor executor = DtpRegistry.getDtpExecutor(x);
            ThreadPoolStats poolStats = MetricsConverter.convert(executor);
            doCollect(poolStats); // 收集操作
        });

        // 针对JUC执行器收集线程池状态
        commonNames.forEach(x -> {
            ExecutorWrapper wrapper = DtpRegistry.getCommonExecutor(x);
            ThreadPoolStats poolStats = MetricsConverter.convert(wrapper);
            doCollect(poolStats); // 收集操作
        });

        publishCollectEvent(); // 发布收集事件CollectEvent
    }

    /** 根据收集类型执行collect操作 */
    private void doCollect(ThreadPoolStats threadPoolStats) {
        try {
            CollectorHandler.getInstance().collect(threadPoolStats, dtpProperties.getCollectorTypes());
        } catch (Exception e) {
            log.error("DynamicTp monitor, metrics collect error.", e);
        }
    }

    /** 发布警报检查事件 */
    private void publishAlarmCheckEvent() {
        AlarmCheckEvent event = new AlarmCheckEvent(this, dtpProperties);
        ApplicationContextHolder.publishEvent(event);
    }

    /** 发布收集事件CollectEvent */
    private void publishCollectEvent() {
        CollectEvent event = new CollectEvent(this, dtpProperties);
        ApplicationContextHolder.publishEvent(event);
    }

    @Override
    public int getOrder() {return Ordered.HIGHEST_PRECEDENCE + 2;}
}
